/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package se.kth.id2212.market;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.*;
import java.util.logging.Level;
import java.util.logging.Logger;

import se.kth.id2212.bankjdbc.Bank;
import se.kth.id2212.bankjdbc.RejectedException;

/**
 *
 * @author apple
 */
@SuppressWarnings("serial")
public class MarketImpl extends UnicastRemoteObject implements Market {

    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private String marketName;
    public static final String TABLE_NAME1 = "TRADER";
    public static final String TABLE_NAME2 = "ITEM";
    public static final String NAME = "name";
    public static final String TRADER = "seller";
    public static final String PRICE = "price";
    public static final String ITEM = "item";
    public static final String MY_ACTIVITY = "activity";
    public static final String PASSWORD = "password";
    private PreparedStatement createTraderStatement;
    private PreparedStatement findTraderStatement;
    private PreparedStatement deleteTraderStatement;
    private PreparedStatement findItemAll;
    private String datasource;
    private String dbms;

    public MarketImpl(String marketName, String datasource, String dbms) throws RemoteException, ClassNotFoundException, SQLException {
        super();
        this.marketName = marketName;
        this.datasource = datasource;
        this.dbms = dbms;
        Connection connection = createDatasource();
        prepareStatements(connection);

    }

    private Connection createDatasource() throws ClassNotFoundException, SQLException {
        Connection connection = getConnection();
        boolean exist = false;
        boolean exist1 = false;
        int tableNameColumn = 3;
        Statement statement = connection.createStatement();
        DatabaseMetaData dbm = connection.getMetaData();
        for (ResultSet rs = dbm.getTables(null, null, null, null); rs.next(); ) {
            if (rs.getString(tableNameColumn).equals(TABLE_NAME1)) {
                exist = true;

            } else if (rs.getString(tableNameColumn).equals(TABLE_NAME2)) {
                exist1 = true;
            }
            if (exist && exist1) {
                rs.close();
                break;
            }
        }
        if(!exist){
            statement.executeUpdate("CREATE TABLE " + TABLE_NAME1 + " ("+NAME +" VARCHAR(32) PRIMARY KEY, "+ PASSWORD +" VARCHAR(32), "+ MY_ACTIVITY +" VARCHAR(128), "+ITEM+" VARCHAR(32))");  
        }
        if(!exist1){
            statement.executeUpdate("CREATE TABLE " + TABLE_NAME2 + " ("+ITEM+" VARCHAR(32) PRIMARY KEY, "+PRICE+" FLOAT, "+TRADER+" VARCHAR(32))");
        }
        return connection;
    }

    private Connection getConnection() throws ClassNotFoundException, SQLException {
        if (dbms.equalsIgnoreCase("derby")) {
            Class.forName("org.apache.derby.jdbc.ClientXADataSource");
            return DriverManager.getConnection("jdbc:derby://localhost:1527/" + datasource + ";create=true");
        } else {
            return null;
        }
    }

    private void prepareStatements(Connection connection) throws SQLException {    
        
        createTraderStatement = connection.prepareStatement(" INSERT INTO " + TABLE_NAME1 + " VALUES (?, ?, null, null) ");
        findTraderStatement = connection.prepareStatement(" SELECT * FROM " + TABLE_NAME1 + " WHERE NAME = ? ");
        deleteTraderStatement = connection.prepareStatement(" DELETE FROM " + TABLE_NAME1 + " WHERE NAME = ? ");
        findItemAll = connection.prepareStatement(" SELECT * FROM " + TABLE_NAME2 );
    }

    @Override
    public synchronized Trader newTrader(String name, String password,Bank bankobj) throws RemoteException, RejectedException {
        Trader trader = null;
        
        try {
            findTraderStatement.setString(1, name);
            ResultSet rs= findTraderStatement.executeQuery();
            if(rs.next()){
                throw new RejectedException("Trader [" + name + "] exist!");
        } else if(password.length() < 8){
               throw new RejectedException("password not allow");
        }
            else{
            
              try {
                  trader = new TraderImpl(name, bankobj, getConnection());
                  createTraderStatement.setString(1, name);
                  createTraderStatement.setString(2, password);
                  
                  int check = createTraderStatement.executeUpdate();
                  if(check ==1){
                      System.out.println("Market: " + marketName + " Trader: " + trader + "has been created for " + name);
                  }
                  else {
                      throw new RejectedException(" failed create" + check);
                  }
            
        } catch (RemoteException ex) {
           // Logger.getLogger(MarketImpl.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SQLException| ClassNotFoundException e) {
            Logger.getLogger(MarketImpl.class.getName()).log(Level.SEVERE, null, e);
        }  
        }
            
        } catch (SQLException ex) {
            Logger.getLogger(MarketImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
        return trader;
    }

    /*@Override
    public synchronized Trader getTrader(String name) {
        Trader trader = new Trader
        return null;
    }*/

    @Override
    public synchronized boolean deleteTrader(String name) {
        try {
            /* if (!hasTrader(name)) {
                 return false;
             }
             traders.remove(name);
             System.out.println("Trader for" + name + "has been deleted");*/
             deleteTraderStatement.setString(1, name);
        } catch (SQLException ex) {
            Logger.getLogger(MarketImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
        return true;

    }

    public synchronized Trader logIn(String name, String password, Bank bankobj) throws RejectedException, RemoteException{
        ResultSet rs=null;
        Trader trader2=null;
        try {
            findTraderStatement.setString(1, name);
            rs = findTraderStatement.executeQuery();
            if(rs.getString(MarketImpl.PASSWORD).equals(password)){
                try {
                    trader2 = new TraderImpl(name,bankobj,getConnection());
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger(MarketImpl.class.getName()).log(Level.SEVERE, null, ex);
                }
            } else {
                throw new RejectedException("Wrong");
            }
            
        } catch (SQLException ex) {
            Logger.getLogger(MarketImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
        return trader2;
    }
    @Override
    public synchronized ResultSet allItem() throws RemoteException {
        ResultSet rs_1=null;
        try {
            rs_1 = findItemAll.executeQuery();
            
        } catch (SQLException ex) {
            Logger.getLogger(MarketImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        /*StringBuffer buffer = new StringBuffer();

        Iterator<Entry<String, Trader>> entrySet = (Iterator<Entry<String, Trader>>) traders.entrySet().iterator();
        while (entrySet.hasNext()) {
            Entry<String, Trader> entry = entrySet.next();
            Trader trader = entry.getValue();
            if (trader.listItem() != null) {
                items.put(entry.getKey(), trader.listItem());
            }

        }

        Iterator<Entry<String, Map<String, Item>>> itemSet = (Iterator<Entry<String, Map<String, Item>>>) items.entrySet().iterator();
        while (itemSet.hasNext()) {
            Entry<String, Map<String, Item>> entry = itemSet.next();
            HashMap<String, Item> item_map = (HashMap<String, Item>) entry.getValue();

            Iterator<Entry<String, Item>> set = (Iterator<Entry<String, Item>>) item_map.entrySet().iterator();

            while (set.hasNext()) {
                Item i = set.next().getValue();
                buffer.append(i.getName()).append("(").append(i.getAmount()).append("):").append(i.getPrice()).append(" SEK - sold by ").append(i.getTrader() + "\n");
            }

        }*/

        return rs_1;
    }

    /*private boolean hasTrader(String name) {
        if (traders.get(name) == null) {
            return false;
        } else {
            return true;
        }
    }*/

}
